import pygame
import time
import os
import sys
from pathlib import Path
import traceback
import pandas as pd
from PyQt5.QtWidgets import (QApplication, QMainWindow, QWidget, QVBoxLayout, QHBoxLayout, 
                            QPushButton, QListWidget, QSlider, QLabel, QFileDialog, 
                            QMessageBox, QProgressBar, QGroupBox, QSpinBox, QCheckBox,
                            QTabWidget, QTextEdit, QLineEdit, QComboBox, QProgressDialog)
from PyQt5.QtCore import Qt, QTimer, QThread, pyqtSignal
from PyQt5.QtGui import QFont, QIcon, QPixmap

try:
    import edge_tts
except ImportError:
    edge_tts = None

# 导入编译后的资源文件
import resources_rc

class PlaybackThread(QThread):
    """播放线程，用于处理时间间隔"""
    finished = pyqtSignal()
    
    def __init__(self, interval_seconds):
        super().__init__()
        self.interval_seconds = interval_seconds
        self._is_running = True
        
    def run(self):
        """运行间隔等待"""
        if self.interval_seconds > 0:
            # 分段等待，以便可以中断
            for _ in range(self.interval_seconds * 10):  # 每0.1秒检查一次
                if not self._is_running:
                    break
                time.sleep(0.1)
        self.finished.emit()
    
    def stop(self):
        """停止等待"""
        self._is_running = False

class TTSWorker(QThread):
    """TTS工作线程"""
    progress = pyqtSignal(int, str)
    finished = pyqtSignal(bool, str)
    
    def __init__(self, excel_path, output_dir, voice_type, selected_column):
        super().__init__()
        self.excel_path = excel_path
        self.output_dir = output_dir
        self.voice_type = voice_type
        self.selected_column = selected_column
        self._is_running = True
        
    def run(self):
        """执行TTS转换"""
        try:
            # 读取Excel文件
            df = pd.read_excel(self.excel_path)
            total = len(df)
            
            # 检查选择的列是否存在
            if self.selected_column not in df.columns:
                self.finished.emit(False, f"错误: 列 '{self.selected_column}' 不存在于Excel文件中")
                return
            
            for index, row in df.iterrows():
                if not self._is_running:
                    break
                    
                text = str(row[self.selected_column])
                filename = f"tts_output_{index+1:03d}.mp3"
                output_path = os.path.join(self.output_dir, filename)
                
                self.progress.emit(index + 1, f"正在处理第 {index + 1} 条: {text[:20]}...")
                
                success = self.edge_tts_convert(text, output_path)
                
                if not success:
                    self.progress.emit(index + 1, f"第 {index + 1} 条转换失败")
            
            self.finished.emit(True, f"转换完成！共处理 {total} 条文本")
            
        except Exception as e:
            self.finished.emit(False, f"转换失败: {str(e)}")
    
    def edge_tts_convert(self, text, output_path):
        """使用Edge-TTS转换"""
        try:
            if edge_tts is None:
                return False
                
            voice = self.voice_type if self.voice_type else "zh-CN-XiaoxiaoNeural"
            communicate = edge_tts.Communicate(text, voice)
            communicate.save_sync(output_path)
            return True
        except Exception:
            return False
    
    def stop(self):
        """停止转换"""
        self._is_running = False

class AudioPlayerGUI(QMainWindow):
    def __init__(self):
        super().__init__()
        self.playback_thread = None
        self.tts_worker = None
        
        # 设置任务栏图标（可选）
        if hasattr(QApplication, 'setWindowIcon'):
            app_icon = QIcon('audio_icon.ico')  # 或者使用资源文件中的图标
            QApplication.setWindowIcon(app_icon)
            
        self.init_ui()
        
         # 设置任务栏缩略图工具按钮（Windows系统）
        self.setup_thumbnail_toolbar()
        self.set_app_icon()
        
        self.init_audio()
        
    def set_app_icon(self):
        """设置应用程序图标"""
        try:
            # 方法1: 使用资源系统
            app_icon = QIcon(":/audio_icon.ico")
            self.setWindowIcon(app_icon)
            QApplication.setWindowIcon(app_icon)
            
        except Exception as e:
            print(f"设置图标失败: {e}")
            # 备用方法：使用内置的Qt图标
            self.setWindowIcon(QIcon.fromTheme("audio-volume-high"))
            
    def init_ui(self):
        """初始化用户界面"""
        self.setWindowTitle("语音模组TTS工具 - 播放器 & TTS转换  作者：赵文昱-TDA")
        self.setGeometry(100, 100, 900, 700)
        
        # 创建标签页
        self.tab_widget = QTabWidget()
        self.setCentralWidget(self.tab_widget)
        
        # 音频播放器标签页
        self.player_tab = QWidget()
        self.setup_player_tab()
        self.tab_widget.addTab(self.player_tab, "音频播放器")
        
        # TTS转换标签页
        self.tts_tab = QWidget()
        self.setup_tts_tab()
        self.tab_widget.addTab(self.tts_tab, "TTS文本转语音")
    def setup_thumbnail_toolbar(self):
        """设置任务栏缩略图工具栏"""
        try:
            # 只有在Windows系统上才设置缩略图工具栏
            if sys.platform == 'win32':
                import ctypes
                from ctypes import wintypes
                
                # 定义Windows API函数
                try:
                    # 尝试设置任务栏按钮
                    self.setup_windows_thumbnail_toolbar()
                except Exception as e:
                    print(f"无法设置任务栏缩略图: {e}")
        except ImportError:
            print("无法导入ctypes，任务栏缩略图功能不可用")
    
    def setup_windows_thumbnail_toolbar(self):
        """Windows系统特定的缩略图工具栏设置"""
        try:
            # 使用Qt的WinId来获取窗口句柄
            hwnd = self.winId()
            
            # 这里可以添加更复杂的Windows API调用来自定义缩略图
            # 但通常Qt会自动处理基本的缩略图预览
            
        except Exception as e:
            print(f"Windows缩略图设置失败: {e}")
            
    def setup_player_tab(self):
        """设置音频播放器标签页"""
        layout = QVBoxLayout(self.player_tab)
        
        # 文件选择区域
        file_group = QGroupBox("文件管理")
        file_layout = QVBoxLayout()
        
        # 文件夹选择按钮
        folder_btn_layout = QHBoxLayout()
        self.folder_label = QLabel("未选择文件夹")
        self.folder_label.setStyleSheet("border: 1px solid gray; padding: 5px;")
        select_folder_btn = QPushButton("选择文件夹")
        select_folder_btn.clicked.connect(self.select_folder)
        folder_btn_layout.addWidget(self.folder_label, 3)
        folder_btn_layout.addWidget(select_folder_btn, 1)
        file_layout.addLayout(folder_btn_layout)
        
        # 文件列表
        self.file_list = QListWidget()
        self.file_list.itemDoubleClicked.connect(self.play_selected_file)
        file_layout.addWidget(QLabel("音频文件列表:"))
        file_layout.addWidget(self.file_list)
        
        file_group.setLayout(file_layout)
        layout.addWidget(file_group)
        
        # 播放控制区域
        control_group = QGroupBox("播放控制")
        control_layout = QVBoxLayout()
        
        # 当前播放信息
        self.current_file_label = QLabel("当前播放: 无")
        self.current_file_label.setStyleSheet("font-weight: bold; color: blue;")
        control_layout.addWidget(self.current_file_label)
        
        # 控制按钮
        btn_layout = QHBoxLayout()
        
        self.prev_btn = QPushButton("上一个 (L)")
        self.prev_btn.clicked.connect(self.play_previous)
        btn_layout.addWidget(self.prev_btn)
        
        self.play_btn = QPushButton("播放")
        self.play_btn.clicked.connect(self.toggle_play)
        btn_layout.addWidget(self.play_btn)
        
        self.pause_btn = QPushButton("暂停 (空格)")
        self.pause_btn.clicked.connect(self.toggle_pause)
        self.pause_btn.setEnabled(False)
        btn_layout.addWidget(self.pause_btn)
        
        self.next_btn = QPushButton("下一个 (N)")
        self.next_btn.clicked.connect(self.play_next)
        btn_layout.addWidget(self.next_btn)
        
        self.stop_btn = QPushButton("停止")
        self.stop_btn.clicked.connect(self.stop_playback)
        btn_layout.addWidget(self.stop_btn)
        
        self.replay_btn = QPushButton("重新播放 (R)")
        self.replay_btn.clicked.connect(self.replay_current)
        self.replay_btn.setEnabled(False)
        btn_layout.addWidget(self.replay_btn)
        
        control_layout.addLayout(btn_layout)
        
        # 音量控制
        volume_layout = QHBoxLayout()
        volume_layout.addWidget(QLabel("音量:"))
        self.volume_slider = QSlider(Qt.Horizontal)
        self.volume_slider.setRange(0, 100)
        self.volume_slider.setValue(70)
        self.volume_slider.valueChanged.connect(self.set_volume)
        volume_layout.addWidget(self.volume_slider)
        self.volume_label = QLabel("70%")
        volume_layout.addWidget(self.volume_label)
        control_layout.addLayout(volume_layout)
        
        # 播放间隔设置
        interval_layout = QHBoxLayout()
        interval_layout.addWidget(QLabel("播放间隔(秒):"))
        self.interval_spin = QSpinBox()
        self.interval_spin.setRange(0, 60)
        self.interval_spin.setValue(3)
        self.interval_spin.valueChanged.connect(self.update_interval)
        interval_layout.addWidget(self.interval_spin)
        
        # 启用间隔复选框
        self.interval_checkbox = QCheckBox("启用间隔")
        self.interval_checkbox.setChecked(True)
        self.interval_checkbox.stateChanged.connect(self.toggle_interval)
        interval_layout.addWidget(self.interval_checkbox)
        
        interval_layout.addStretch()
        control_layout.addLayout(interval_layout)
        
        # 播放模式
        mode_layout = QHBoxLayout()
        mode_layout.addWidget(QLabel("播放模式:"))
        self.loop_checkbox = QCheckBox("循环播放")
        mode_layout.addWidget(self.loop_checkbox)
        self.random_checkbox = QCheckBox("随机播放")
        mode_layout.addWidget(self.random_checkbox)
        mode_layout.addStretch()
        control_layout.addLayout(mode_layout)
        
        control_group.setLayout(control_layout)
        layout.addWidget(control_group)
        
        # 状态栏
        self.status_label = QLabel("就绪")
        self.status_label.setStyleSheet("border: 1px solid gray; padding: 5px;")
        layout.addWidget(self.status_label)
        
        # 初始化变量
        self.audio_files = []
        self.current_index = -1
        self.is_playing = False
        self.is_paused = False
        self.interval_seconds = 3
        self.interval_enabled = True
        self.waiting_for_interval = False
        
        # 设置定时器
        self.timer = QTimer()
        self.timer.timeout.connect(self.update_ui)
        self.timer.start(100)
        
    def setup_tts_tab(self):
        """设置TTS转换标签页"""
        layout = QVBoxLayout(self.tts_tab)
        
        # Excel文件选择
        excel_group = QGroupBox("Excel文件选择")
        excel_layout = QVBoxLayout()
        
        excel_btn_layout = QHBoxLayout()
        self.excel_path_label = QLabel("未选择Excel文件")
        self.excel_path_label.setStyleSheet("border: 1px solid gray; padding: 5px;")
        select_excel_btn = QPushButton("选择Excel文件")
        select_excel_btn.clicked.connect(self.select_excel_file)
        excel_btn_layout.addWidget(self.excel_path_label, 3)
        excel_btn_layout.addWidget(select_excel_btn, 1)
        excel_layout.addLayout(excel_btn_layout)
        
        # 列选择
        column_layout = QHBoxLayout()
        column_layout.addWidget(QLabel("选择文本列:"))
        self.column_combo = QComboBox()
        self.column_combo.setEnabled(False)
        column_layout.addWidget(self.column_combo)
        column_layout.addStretch()
        excel_layout.addLayout(column_layout)
        
        excel_group.setLayout(excel_layout)
        layout.addWidget(excel_group)
        
        # 输出目录选择
        output_group = QGroupBox("输出设置")
        output_layout = QVBoxLayout()
        
        output_btn_layout = QHBoxLayout()
        self.output_dir_label = QLabel("未选择输出目录")
        self.output_dir_label.setStyleSheet("border: 1px solid gray; padding: 5px;")
        select_output_btn = QPushButton("选择输出目录")
        select_output_btn.clicked.connect(self.select_output_dir)
        output_btn_layout.addWidget(self.output_dir_label, 3)
        output_btn_layout.addWidget(select_output_btn, 1)
        output_layout.addLayout(output_btn_layout)
        
        output_group.setLayout(output_layout)
        layout.addWidget(output_group)
        
        # TTS引擎设置
        engine_group = QGroupBox("TTS引擎设置")
        engine_layout = QVBoxLayout()
        
        # 语音选择
        voice_layout = QHBoxLayout()
        voice_layout.addWidget(QLabel("语音类型:"))
        self.voice_combo = QComboBox()
        self.voice_combo.addItems(["zh-CN-XiaoxiaoNeural", "zh-CN-YunxiNeural", "zh-CN-YunyeNeural"])
        voice_layout.addWidget(self.voice_combo)
        voice_layout.addStretch()
        engine_layout.addLayout(voice_layout)
        
        engine_group.setLayout(engine_layout)
        layout.addWidget(engine_group)
        
        # 转换按钮
        convert_btn_layout = QHBoxLayout()
        self.convert_btn = QPushButton("开始转换")
        self.convert_btn.clicked.connect(self.start_tts_conversion)
        self.convert_btn.setStyleSheet("font-size: 14px; padding: 10px;")
        convert_btn_layout.addWidget(self.convert_btn)
        
        self.stop_convert_btn = QPushButton("停止转换")
        self.stop_convert_btn.clicked.connect(self.stop_tts_conversion)
        self.stop_convert_btn.setEnabled(False)
        convert_btn_layout.addWidget(self.stop_convert_btn)
        
        layout.addLayout(convert_btn_layout)
        
        # 进度显示
        self.tts_progress_label = QLabel("就绪")
        self.tts_progress_label.setStyleSheet("border: 1px solid gray; padding: 5px;")
        layout.addWidget(self.tts_progress_label)
        
        # 依赖检查
        self.check_dependencies()
        
    def check_dependencies(self):
        """检查依赖库"""
        if edge_tts is None:
            self.tts_progress_label.setText("缺少依赖: edge-tts (pip install edge-tts)")
        
    def select_excel_file(self):
        """选择Excel文件"""
        file_path, _ = QFileDialog.getOpenFileName(
            self, "选择Excel文件", "", "Excel文件 (*.xlsx *.xls)"
        )
        if file_path:
            self.excel_path_label.setText(file_path)
            self.load_excel_columns(file_path)
    
    def load_excel_columns(self, file_path):
        """加载Excel文件的列名"""
        try:
            df = pd.read_excel(file_path)
            columns = df.columns.tolist()
            
            self.column_combo.clear()
            self.column_combo.addItems(columns)
            self.column_combo.setEnabled(True)
            
            # 默认选择第一列
            if columns:
                self.column_combo.setCurrentIndex(0)
                
        except Exception as e:
            QMessageBox.warning(self, "错误", f"读取Excel文件失败: {str(e)}")
            self.column_combo.setEnabled(False)
    
    def select_output_dir(self):
        """选择输出目录"""
        dir_path = QFileDialog.getExistingDirectory(self, "选择输出目录")
        if dir_path:
            self.output_dir_label.setText(dir_path)
    
    def start_tts_conversion(self):
        """开始TTS转换"""
        excel_path = self.excel_path_label.text()
        output_dir = self.output_dir_label.text()
        selected_column = self.column_combo.currentText()
        
        if excel_path == "未选择Excel文件" or not os.path.exists(excel_path):
            QMessageBox.warning(self, "警告", "请选择有效的Excel文件")
            return
        
        if output_dir == "未选择输出目录":
            QMessageBox.warning(self, "警告", "请选择输出目录")
            return
        
        if not selected_column:
            QMessageBox.warning(self, "警告", "请选择文本列")
            return
        
        # 创建输出目录
        os.makedirs(output_dir, exist_ok=True)
        
        # 启动转换线程
        self.tts_worker = TTSWorker(
            excel_path, output_dir, 
            self.voice_combo.currentText(),
            selected_column
        )
        self.tts_worker.progress.connect(self.update_tts_progress)
        self.tts_worker.finished.connect(self.tts_finished)
        
        self.convert_btn.setEnabled(False)
        self.stop_convert_btn.setEnabled(True)
        self.tts_progress_label.setText("开始转换...")
        
        self.tts_worker.start()
    
    def stop_tts_conversion(self):
        """停止TTS转换"""
        if self.tts_worker and self.tts_worker.isRunning():
            self.tts_worker.stop()
            self.tts_worker.wait()
            self.tts_progress_label.setText("转换已停止")
        
        self.convert_btn.setEnabled(True)
        self.stop_convert_btn.setEnabled(False)
    
    def update_tts_progress(self, current, message):
        """更新TTS进度"""
        self.tts_progress_label.setText(message)
    
    def tts_finished(self, success, message):
        """TTS转换完成"""
        self.convert_btn.setEnabled(True)
        self.stop_convert_btn.setEnabled(False)
        
        if success:
            QMessageBox.information(self, "完成", message)
        else:
            QMessageBox.warning(self, "错误", message)
        
        self.tts_progress_label.setText(message)
    
    # 以下是音频播放器的方法（保持不变）
    def init_audio(self):
        """初始化音频系统"""
        try:
            pygame.mixer.init()
            pygame.mixer.music.set_volume(0.7)
            self.update_status("音频系统初始化成功")
        except Exception as e:
            self.show_error(f"音频初始化失败: {e}")
    
    def update_interval(self, value):
        """更新间隔时间"""
        self.interval_seconds = value
    
    def toggle_interval(self, state):
        """切换间隔功能"""
        self.interval_enabled = (state == Qt.Checked)
    
    def select_folder(self):
        """选择文件夹"""
        folder_path = QFileDialog.getExistingDirectory(self, "选择音频文件夹")
        if folder_path:
            self.load_audio_files(folder_path)
    
    def load_audio_files(self, folder_path):
        """加载音频文件"""
        self.folder_label.setText(folder_path)
        self.audio_files = []
        self.file_list.clear()
        
        supported_extensions = ['.mp3', '.wav', '.ogg']
        folder = Path(folder_path)
        
        for ext in supported_extensions:
            files = list(folder.glob(f"*{ext}"))
            for file in files:
                self.audio_files.append(file)
                self.file_list.addItem(file.name)
        
        if self.audio_files:
            self.update_status(f"找到 {len(self.audio_files)} 个音频文件")
            self.play_btn.setEnabled(True)
            self.current_index = 0
            self.highlight_current_file()
        else:
            self.update_status("未找到支持的音频文件")
            self.play_btn.setEnabled(False)
    
    def highlight_current_file(self):
        """高亮显示当前播放的文件"""
        for i in range(self.file_list.count()):
            if i == self.current_index:
                self.file_list.item(i).setBackground(Qt.lightGray)
            else:
                self.file_list.item(i).setBackground(Qt.white)
    
    def play_audio(self, index):
        """播放指定索引的音频文件"""
        if not self.audio_files or index < 0 or index >= len(self.audio_files):
            return
        
        try:
            self.current_index = index
            audio_file = self.audio_files[index]
            
            pygame.mixer.music.load(str(audio_file))
            pygame.mixer.music.play()
            
            self.is_playing = True
            self.is_paused = False
            self.waiting_for_interval = False
            
            self.current_file_label.setText(f"当前播放: {audio_file.name}")
            self.update_status(f"正在播放: {audio_file.name}")
            self.highlight_current_file()
            
            self.play_btn.setText("停止")
            self.pause_btn.setEnabled(True)
            self.pause_btn.setText("暂停")
            self.replay_btn.setEnabled(True)
            
        except Exception as e:
            self.show_error(f"播放失败: {e}")
    
    def replay_current(self):
        """重新播放当前文件"""
        if self.is_playing:
            self.stop_playback()
        if self.audio_files and self.current_index >= 0:
            self.play_audio(self.current_index)
            self.update_status("重新播放当前文件")
    
    def start_interval_wait(self):
        """开始间隔等待"""
        if self.interval_enabled and self.interval_seconds > 0:
            self.waiting_for_interval = True
            self.update_status(f"等待 {self.interval_seconds} 秒后播放下一首...")
            
            if self.playback_thread and self.playback_thread.isRunning():
                self.playback_thread.stop()
                self.playback_thread.wait()
            
            self.playback_thread = PlaybackThread(self.interval_seconds)
            self.playback_thread.finished.connect(self.interval_finished)
            self.playback_thread.start()
        else:
            self.play_next()
    
    def interval_finished(self):
        """间隔等待完成"""
        if self.waiting_for_interval:
            self.waiting_for_interval = False
            self.play_next()
    
    def toggle_play(self):
        """切换播放/停止状态"""
        if self.is_playing:
            self.stop_playback()
        else:
            if self.audio_files:
                self.play_audio(self.current_index)
    
    def toggle_pause(self):
        """切换暂停/恢复状态"""
        if self.is_playing:
            if self.is_paused:
                pygame.mixer.music.unpause()
                self.is_paused = False
                self.pause_btn.setText("暂停")
                self.update_status("播放恢复")
            else:
                pygame.mixer.music.pause()
                self.is_paused = True
                self.pause_btn.setText("恢复")
                self.update_status("播放暂停")
    
    def stop_playback(self):
        """停止播放"""
        pygame.mixer.music.stop()
        self.is_playing = False
        self.is_paused = False
        self.waiting_for_interval = False
        
        if self.playback_thread and self.playback_thread.isRunning():
            self.playback_thread.stop()
            self.playback_thread.wait()
        
        self.play_btn.setText("播放")
        self.pause_btn.setEnabled(False)
        self.replay_btn.setEnabled(False)
        self.update_status("播放停止")
    
    def play_next(self):
        """播放下一个文件"""
        if self.audio_files:
            if self.random_checkbox.isChecked():
                import random
                next_index = random.randint(0, len(self.audio_files) - 1)
            else:
                next_index = (self.current_index + 1) % len(self.audio_files)
            
            if next_index == 0 and not self.loop_checkbox.isChecked():
                self.stop_playback()
                self.update_status("播放完成")
            else:
                self.play_audio(next_index)
    
    def play_previous(self):
        """播放上一个文件"""
        if self.audio_files:
            prev_index = (self.current_index - 1) % len(self.audio_files)
            self.play_audio(prev_index)
    
    def play_selected_file(self, item):
        """播放选中的文件"""
        index = self.file_list.row(item)
        self.play_audio(index)
    
    def set_volume(self, value):
        """设置音量"""
        volume = value / 100.0
        pygame.mixer.music.set_volume(volume)
        self.volume_label.setText(f"{value}%")
    
    def update_ui(self):
        """更新UI状态"""
        if self.is_playing and not self.is_paused and not self.waiting_for_interval:
            if not pygame.mixer.music.get_busy():
                self.start_interval_wait()
    
    def update_status(self, message):
        """更新状态信息"""
        self.status_label.setText(message)
    
    def show_error(self, message):
        """显示错误信息"""
        QMessageBox.critical(self, "错误", message)
        self.update_status(f"错误: {message}")
    
    def keyPressEvent(self, event):
        """键盘事件处理"""
        if event.key() == Qt.Key_Space:
            self.toggle_pause()
        elif event.key() == Qt.Key_N:
            self.play_next()
        elif event.key() == Qt.Key_L:
            self.play_previous()
        elif event.key() == Qt.Key_S:
            self.stop_playback()
        elif event.key() == Qt.Key_R:
            self.replay_current()
        elif event.key() == Qt.Key_I:
            self.interval_checkbox.setChecked(not self.interval_checkbox.isChecked())
    
    def closeEvent(self, event):
        """关闭事件处理"""
        self.stop_playback()
        if self.tts_worker and self.tts_worker.isRunning():
            self.tts_worker.stop()
            self.tts_worker.wait()
        pygame.mixer.quit()
        event.accept()

def main():
    # 初始化应用
    app = QApplication(sys.argv)
    
    # 设置应用样式
    app.setStyle('Fusion')
    
    # 创建并显示主窗口
    player = AudioPlayerGUI()
    player.show()
    
    # 运行应用
    sys.exit(app.exec_())

if __name__ == "__main__":
    main()